#ifndef _COM_DEF_H_
#define _COM_DEF_H_

#include "stdint.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define COM_DAT_NULL 0x7FFF

	typedef enum
	{
		COM_RX_IDLE,   
		COM_RX_RCV,	   
		COM_RX_RCVEND, 
		COM_RX_WAIT,   
		COM_RX_TIMEOUT 

	} com_rcv_state_type;

	typedef enum
	{
		COM_TX_IDLE, 
		COM_TX_XMIT	 
	} com_snd_state_type;

	typedef enum
	{
		COM_PAR_NONE_1S, 
		COM_PAR_NONE_2S, 
		COM_PAR_ODD,	 
		COM_PAR_EVEN	 
	} com_parity_type;

	typedef union
	{
		uint32_t St;

		struct
		{
			uint8_t run_en;	 
			uint8_t port_st; 
			uint8_t err_hal;
			uint8_t ov_mode; 
		} bits;
	} com_state_type;

	typedef struct
	{
		void (*rx_cmd)(uint8_t xEnable); 
		void (*tx_cmd)(uint8_t xEnable); 
		void (*hal_send)(uint8_t dat);	 
		int16_t (*hal_read)(void);		 
		void (*rcv_st_clr_hal)(void);	 
		void (*snd_st_clr_hal)(void);	 

		uint8_t (*idle_check)(void);				 
		int16_t (*wait_for_idle)(uint16_t time_out); 
		void (*rcv_st_clr)(void);					 
		void (*snd_st_clr)(void);					 

		void (*snd_byte)(uint8_t ch);
		int16_t (*rcv_byte)(void);								 
		void (*snd_string)(const char *str);					 
		void (*snd_data)(const uint8_t *dat, uint16_t len);		 
		uint16_t (*rcv_multi)(uint8_t *dat, uint16_t buff_size); 
		uint16_t (*rcv_line)(uint8_t *dat, uint16_t len_max);	 
		uint16_t (*rcv_end_4B)(uint8_t *dat, uint16_t len_max, uint32_t symbol);
		uint16_t (*rcv_end_3B)(uint8_t *dat, uint16_t len_max, uint32_t symbol);
		uint16_t (*rcv_end_2B)(uint8_t *dat, uint16_t len_max, uint16_t symbol);
		uint16_t (*rcv_remain_amount)(void); 
		uint16_t (*snd_remain_amount)(void); 

		int16_t (*tail_rcv_byte)(int16_t bsite);
		uint16_t (*tail_rcv_multi)(int16_t bsite, uint8_t *dat, int16_t len);
		uint16_t (*tail_rcv_line)(int16_t bsite, uint8_t *dat, int16_t len_max);
		uint16_t (*tail_rcv_end_4B)(int16_t bsite, uint8_t *dat, int16_t len_max, uint32_t symbol);
		uint16_t (*tail_rcv_end_3B)(int16_t bsite, uint8_t *dat, int16_t len_max, uint32_t symbol);
		uint16_t (*tail_rcv_end_2B)(int16_t bsite, uint8_t *dat, int16_t len_max, uint16_t symbol);
	} com_fun_type;

#define COM_EVENT_RCVEND 1
#define COM_EVENT_TIMEOUT 2
#define COM_EVENT_IDLE_OK 4

	typedef struct
	{
		com_state_type St;

		uint16_t rcv_end_time_cnt;
		uint16_t rcv_end_time_sv; 

		uint16_t act_time_cnt;
		uint16_t act_time_max;
		uint16_t idle_time_cnt;
		uint16_t master_wait_time_cnt;
		uint16_t master_wait_time_sv; 

		uint8_t b_auto_send;	
		uint8_t b_timer_on;		
		uint8_t b_master_mode;	
		uint8_t rcv_end_char;	
		uint8_t rcv_start_char; 
		uint32_t rcv_squence;	

		volatile com_snd_state_type snd_st; 
		volatile com_rcv_state_type rcv_st; 

		uint16_t rx_buff_size;
		uint16_t tx_buff_size;

		uint16_t index_tx_fill;			 
		volatile uint16_t index_tx_send; 
		uint16_t index_rx_rcv;			 
		uint16_t index_rx_get;			 

		uint8_t *rx_buff; 
		uint8_t *tx_buff; 

		uint16_t os_event_base;
		uint16_t rcv_end_keep_sv; 
		uint32_t usr_timer_cnt;	  

		struct 
		{
			volatile uint8_t st_dir_ctr_req; 
			volatile uint16_t dma_send_amount;
			uint16_t timeout_cnt;
			uint16_t timeout_set;
		} hal_ctr;

		void (*rx_call_back)(uint8_t ch);	   
		void (*os_event_send)(uint16_t event); 

		const com_fun_type *fun;
	} com_obj_type;

	void com_tx_cmd(com_obj_type *com, uint8_t en_or_dis);
	void com_rx_cmd(com_obj_type *com, uint8_t en_or_dis);
	uint8_t com_idle_check(com_obj_type *com);
	int16_t com_wait_for_idle(com_obj_type *com, uint16_t time_out);
	void com_master_mode_en(com_obj_type *com);
	void com_master_mode_dis(com_obj_type *com);
	int16_t com_rcv_st_clr(com_obj_type *com);
	int16_t com_snd_st_clr(com_obj_type *com);
	void com_rx_rcv_keep_old(com_obj_type *com, uint8_t ch);
	void com_rx_rcv_keep_new(com_obj_type *com, uint8_t ch);
	void com_rx_rcv_prev(com_obj_type *com);
	void com_rx_rcv(com_obj_type *com, uint8_t ch);

	void com_end_time_set(com_obj_type *com, uint16_t sv);
	void com_wait_time_set(com_obj_type *com, uint16_t sv);
	void com_timer_en(com_obj_type *com);
	void com_timer_dis(com_obj_type *com);
	void com_timer_run(com_obj_type *com);
	uint16_t com_timer_cal(uint32_t baud, uint16_t bits, uint16_t min, uint16_t max); 

	void com_snd_string(com_obj_type *com, const char *str);
	void com_snd_data(com_obj_type *com, const uint8_t *dat, uint16_t len);
	void com_snd_byte(com_obj_type *com, uint8_t ch);

	int16_t com_rcv_byte(com_obj_type *com);
	uint16_t com_rcv_multi(com_obj_type *com, uint8_t *dat, uint16_t buff_size);
	uint16_t com_rcv_line(com_obj_type *com, uint8_t *dat, uint16_t len_max);					 
	uint16_t com_rcv_end_4B(com_obj_type *com, uint8_t *dat, uint16_t len_max, uint32_t symbol); 
	uint16_t com_rcv_end_3B(com_obj_type *com, uint8_t *dat, uint16_t len_max, uint32_t symbol); 
	uint16_t com_rcv_end_2B(com_obj_type *com, uint8_t *dat, uint16_t len_max, uint16_t symbol); 
    uint16_t com_rcv_end_1B(com_obj_type *com, uint8_t *dat, uint16_t len_max, uint8_t symbol);  
	uint16_t com_rcv_remain_amount(com_obj_type *com);
	uint16_t com_snd_remain_amount(com_obj_type *com);

	int16_t com_tail_rcv_byte(com_obj_type *com, int16_t bsite);
	uint16_t com_tail_rcv_multi(com_obj_type *com, int16_t bsite, uint8_t *dat, int16_t len);
	uint16_t com_tail_rcv_line(com_obj_type *com, int16_t bsite, uint8_t *dat, int16_t len_max);
	uint16_t com_tail_rcv_end_4B(com_obj_type *com, int16_t bsite, uint8_t *dat, int16_t len_max, uint32_t symbol);
	uint16_t com_tail_rcv_end_3B(com_obj_type *com, int16_t bsite, uint8_t *dat, int16_t len_max, uint32_t symbol);
	uint16_t com_tail_rcv_end_2B(com_obj_type *com, int16_t bsite, uint8_t *dat, int16_t len_max, uint16_t symbol);

#define com_api_make(name, obj)                                                         \
                                                                                        \
	static uint8_t name##_idle_check(void);                                             \
	static int16_t name##_wait_for_idle(uint16_t time_out);                             \
	static void name##_rcv_st_clr(void);                                                \
	static void name##_snd_st_clr(void);                                                \
	static void name##_snd_byte(uint8_t ch);                                            \
	static int16_t name##_rcv_byte(void);                                               \
	static void name##_snd_string(const char *str);                                     \
	static void name##_snd_data(const uint8_t *dat, uint16_t len);                      \
	static uint16_t name##_rcv_multi(uint8_t *dat, uint16_t buff_size);                 \
	static uint16_t name##_rcv_line(uint8_t *dat, uint16_t len_max);                    \
	static uint16_t name##_rcv_end_4B(uint8_t *dat, uint16_t len_max, uint32_t symbol); \
	static uint16_t name##_rcv_end_3B(uint8_t *dat, uint16_t len_max, uint32_t symbol); \
	static uint16_t name##_rcv_end_2B(uint8_t *dat, uint16_t len_max, uint16_t symbol); \
	static uint16_t name##_rcv_remain_amount(void);                                     \
	static uint16_t name##_snd_remain_amount(void);                                     \
	static int16_t name##_tail_rcv_byte(int16_t bsite);                                 \
	static uint16_t name##_tail_rcv_multi(int16_t bsite, uint8_t *dat, int16_t len);    \
	static uint16_t name##_tail_rcv_line(int16_t bsite, uint8_t *dat, int16_t len_max); \
	static uint16_t name##_tail_rcv_end_4B(                                             \
		int16_t bsite, uint8_t *dat, int16_t len_max, uint32_t symbol);                 \
	static uint16_t name##_tail_rcv_end_3B(                                             \
		int16_t bsite, uint8_t *dat, int16_t len_max, uint32_t symbol);                 \
	static uint16_t name##_tail_rcv_end_2B(                                             \
		int16_t bsite, uint8_t *dat, int16_t len_max, uint16_t symbol);                 \
                                                                                        \
	static uint8_t name##_idle_check(void)                                              \
	{                                                                                   \
		return com_idle_check(&obj);                                                    \
	}                                                                                   \
	static int16_t name##_wait_for_idle(uint16_t time_out)                              \
	{                                                                                   \
		return com_wait_for_idle(&obj, time_out);                                       \
	}                                                                                   \
	static void name##_rcv_st_clr(void)                                                 \
	{                                                                                   \
		com_rcv_st_clr(&obj);                                                           \
	}                                                                                   \
	static void name##_snd_st_clr(void)                                                 \
	{                                                                                   \
		com_snd_st_clr(&obj);                                                           \
	}                                                                                   \
	static void name##_snd_byte(uint8_t ch)                                             \
	{                                                                                   \
		com_snd_byte(&obj, ch);                                                         \
	}                                                                                   \
	static int16_t name##_rcv_byte(void)                                                \
	{                                                                                   \
		return com_rcv_byte(&obj);                                                      \
	}                                                                                   \
	static void name##_snd_string(const char *str)                                      \
	{                                                                                   \
		com_snd_string(&obj, str);                                                      \
	}                                                                                   \
	static void name##_snd_data(const uint8_t *dat, uint16_t len)                       \
	{                                                                                   \
		com_snd_data(&obj, dat, len);                                                   \
	}                                                                                   \
	static uint16_t name##_rcv_multi(uint8_t *dat, uint16_t buff_size)                  \
	{                                                                                   \
		return com_rcv_multi(&obj, dat, buff_size);                                     \
	}                                                                                   \
	static uint16_t name##_rcv_line(uint8_t *dat, uint16_t len_max)                     \
	{                                                                                   \
		return com_rcv_line(&obj, dat, len_max);                                        \
	}                                                                                   \
	static uint16_t name##_rcv_end_4B(uint8_t *dat, uint16_t len_max, uint32_t symbol)  \
	{                                                                                   \
		return com_rcv_end_4B(&obj, dat, len_max, symbol);                              \
	}                                                                                   \
	static uint16_t name##_rcv_end_3B(uint8_t *dat, uint16_t len_max, uint32_t symbol)  \
	{                                                                                   \
		return com_rcv_end_3B(&obj, dat, len_max, symbol);                              \
	}                                                                                   \
	static uint16_t name##_rcv_end_2B(uint8_t *dat, uint16_t len_max, uint16_t symbol)  \
	{                                                                                   \
		return com_rcv_end_2B(&obj, dat, len_max, symbol);                              \
	}                                                                                   \
	static uint16_t name##_rcv_remain_amount(void)                                      \
	{                                                                                   \
		return com_rcv_remain_amount(&obj);                                             \
	}                                                                                   \
	static uint16_t name##_snd_remain_amount(void)                                      \
	{                                                                                   \
		return com_snd_remain_amount(&obj);                                             \
	}                                                                                   \
	static int16_t name##_tail_rcv_byte(int16_t bsite)                                  \
	{                                                                                   \
		return com_tail_rcv_byte(&obj, bsite);                                          \
	}                                                                                   \
	static uint16_t name##_tail_rcv_multi(int16_t bsite, uint8_t *dat, int16_t len)     \
	{                                                                                   \
		return com_tail_rcv_multi(&obj, bsite, dat, len);                               \
	}                                                                                   \
	static uint16_t name##_tail_rcv_line(int16_t bsite, uint8_t *dat, int16_t len_max)  \
	{                                                                                   \
		return com_tail_rcv_line(&obj, bsite, dat, len_max);                            \
	}                                                                                   \
	static uint16_t name##_tail_rcv_end_4B(                                             \
		int16_t bsite, uint8_t *dat, int16_t len_max, uint32_t symbol)                  \
	{                                                                                   \
		return com_tail_rcv_end_4B(&obj, bsite, dat, len_max, symbol);                  \
	}                                                                                   \
	static uint16_t name##_tail_rcv_end_3B(                                             \
		int16_t bsite, uint8_t *dat, int16_t len_max, uint32_t symbol)                  \
	{                                                                                   \
		return com_tail_rcv_end_3B(&obj, bsite, dat, len_max, symbol);                  \
	}                                                                                   \
	static uint16_t name##_tail_rcv_end_2B(                                             \
		int16_t bsite, uint8_t *dat, int16_t len_max, uint16_t symbol)                  \
	{                                                                                   \
		return com_tail_rcv_end_2B(&obj, bsite, dat, len_max, symbol);                  \
	}                                                                                   \
	static const com_fun_type name##_com_fun = {                                        \
		com_rx_enable,                                                                  \
		com_tx_enable,                                                                  \
		com_hal_send,                                                                   \
		com_hal_read,                                                                   \
		com_rcv_st_clr_hal,           \
		com_snd_st_clr_hal,           \
                                                                                        \
		name##_idle_check,                                                              \
		name##_wait_for_idle,                                                           \
		name##_rcv_st_clr,                                                              \
		name##_snd_st_clr,                                                              \
                                                                                        \
		name##_snd_byte,                                                                \
		name##_rcv_byte,                                                                \
		name##_snd_string,                                                              \
		name##_snd_data,                                                                \
		name##_rcv_multi,                                                               \
		name##_rcv_line,                                                                \
		name##_rcv_end_4B,                                                              \
		name##_rcv_end_3B,                                                              \
		name##_rcv_end_2B,                                                              \
		name##_rcv_remain_amount,                                                       \
		name##_snd_remain_amount,                                                       \
                                                                                        \
		name##_tail_rcv_byte,                                                           \
		name##_tail_rcv_multi,                                                          \
		name##_tail_rcv_line,                                                           \
		name##_tail_rcv_end_4B,                                                         \
		name##_tail_rcv_end_3B,                                                         \
		name##_tail_rcv_end_2B}

#define com_api_ref(name) extern const qcom_api_type name##_api
#define com_api_name(name) &name##_com_fun
#define com_api_link(name, obj) obj.fun = &name##_api

#ifdef __cplusplus
}
#endif

#endif 
